/**
* Copyright (c) 2010-17 David Dearing
*/
package com.dpdearing.sandbox.gpsemulator.client;
import com.dpdearing.sandbox.gpsemulator.common.LocationServiceAsync;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.maps.client.MapOptions;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.base.LatLng;
import com.google.gwt.maps.client.events.click.ClickMapEvent;
import com.google.gwt.maps.client.events.click.ClickMapHandler;
import com.google.gwt.maps.client.overlays.Marker;
import com.google.gwt.maps.client.overlays.MarkerOptions;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.TextBox;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class GpsEmulator implements EntryPoint, ClickMapHandler {
/**
* The default emulator hostname port
*/
static private final String DEFAULT_HOST = "localhost";
static private final int DEFAULT_PORT = 5554;
static private final String SUCCESS_STYLE = "success";
static private final String ERROR_STYLE = "error";
/**
* Create a remote service proxy to talk to the server-side Location service.
*/
private final LocationServiceAsync _service =
LocationServiceAsync.Util.getInstance();
/**
* The map and current marker shown
*/
private MapWidget _map;
private Marker _currentMarker = null;
/**
* The textboxes, button, and info label for configuring the host and port.
*/
private TextBox _hostname;
private TextBox _port;
private Button _button;
private Label _info;
/**
* This is the entry point method.
*/
public void onModuleLoad() {
// This _should_ be using LoadApi.go(onLoad, loadLibraries, sensor) to
// then call buildUi() from within a Runnable (onLoad) but this does not
// seem to work. The map does not appear until after resizing the browser
// window. Instead, the Google Maps API is loaded directly from a <script>
// tag at the bottom of index.html, which seems to consistently load before
// onModuleLoad is called.
buildUi();
}
/**
* Initialize the UI
*/
private void buildUi() {
// Create textboxes and set default hostname and port
_hostname = new TextBox();
_hostname.setText(DEFAULT_HOST);
_hostname.getElement().setPropertyString("placeholder", "hostname");
_port = new TextBox();
_port.setText(String.valueOf(DEFAULT_PORT));
_port.getElement().setPropertyString("placeholder", "port");
// Create button to connect
_button = new Button("Connect");
// Create the info/status label, initially not visible
_info = new InlineLabel();
_info.setVisible(false);
// register the button action
_button.addClickHandler(new ClickHandler() {
public void onClick(final ClickEvent event) {
final String hostname = _hostname.getText();
final int port = Integer.valueOf(_port.getText());
new PortAsyncCallback(hostname, port).execute();
}
});
// Create panel for textbox, button and info label
final FlowPanel div = new FlowPanel();
div.setStylePrimaryName("emulator-controls");
_hostname.setStyleName("emulator-hostname");
_port.setStyleName("emulator-port");
_button.setStyleName("emulator-connect");
_info.setStyleName("emulator-info");
div.add(_hostname);
div.add(_port);
div.add(_button);
div.add(_info);
// Create a map centered on Cawker City, KS USA
final MapOptions opts = MapOptions.newInstance();
final LatLng cawkerCity = LatLng.newInstance(39.509, -98.434);
opts.setCenter(cawkerCity);
opts.setZoom(4);
_map = new MapWidget(opts);
// Register map click handler
_map.addClickHandler(this);
// add the controls before the map so that the div doesn't cover the map
RootLayoutPanel.get().add(div);
RootLayoutPanel.get().add(_map);
}
/**
* Handle a map click event
*/
public void onEvent(ClickMapEvent clickMapEvent) {
final LatLng point = clickMapEvent.getMouseEvent().getLatLng();
// clear the last-placed marker ...
if (_currentMarker != null) {
_currentMarker.clear();
}
// ... and add the new marker
MarkerOptions opts = MarkerOptions.newInstance();
opts.setMap(_map);
opts.setPosition(point);
_currentMarker = Marker.newInstance(opts);
// set the location
new GeoFixAsyncCallback(point.getLatitude(), point.getLongitude()).execute();
}
private void setSuccessMessage(String message) {
_info.addStyleDependentName(SUCCESS_STYLE);
_info.setText(message);
_info.setVisible(true);
}
private void setErrorMessage(String message) {
_info.addStyleDependentName(ERROR_STYLE);
_info.setText(message);
_info.setVisible(true);
}
private void clearMessage() {
_info.setText("");
_info.removeStyleDependentName(ERROR_STYLE);
_info.removeStyleDependentName(SUCCESS_STYLE);
_info.setVisible(false);
}
/**
* Asynchronous callback for setting the telnet port.
*/
private class PortAsyncCallback implements AsyncCallback<Void>, Command {
private final String _hostname;
private final int _port;
/**
* Constructor
*
* @param hostname the hostname
* @param port the port
*/
public PortAsyncCallback(final String hostname, final int port) {
_hostname = hostname;
_port = port;
}
/**
* Success!
*
* @param result void
*/
public void onSuccess(final Void result) {
setSuccessMessage("Connected to " + _hostname + ":" + _port);
}
/**
* Oh no!
*/
public void onFailure(final Throwable caught) {
setErrorMessage("Error connecting to " + _hostname + ":" + _port + " - "
+ caught.getLocalizedMessage());
}
/**
* Execute service method
*/
public void execute() {
clearMessage();
_service.connect(_hostname, _port, this);
}
}
/**
* Asynchronous callback for changing the emulator's location
*/
private class GeoFixAsyncCallback implements AsyncCallback<Void>, Command {
private final double _latitude;
private final double _longitude;
/**
* Constructor.
*
* @param latitude
* latitude
* @param longitude
* longitude
*/
public GeoFixAsyncCallback(final double latitude, final double longitude) {
_latitude = latitude;
_longitude = longitude;
}
/**
* Success!
*
* @param result void
*/
public void onSuccess(final Void result) {
setSuccessMessage("geo fix " + _longitude + " " + _latitude);
}
/**
* Oh no!
*/
public void onFailure(final Throwable caught) {
setErrorMessage("Error setting location: " + caught.getLocalizedMessage());
}
/**
* Execute service method
*/
public void execute() {
clearMessage();
_service.setLocation(_latitude, _longitude, this);
}
}
}